package com.lomboardrisk.app.ee_new.service.impl;

import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

import org.apache.log4j.Logger;

import com.lomboardrisk.app.ee_new.service.FlexiblePageService;
import com.lomboardrisk.app.ee_new.web.jsonUtils.MixBean;
import com.lomboardrisk.app.ee_new.xsd.jqGrid.cfgItems.JSONManipulateCfg;
import com.lomboardrisk.app.ee_new.xsd.jqGrid.cfgItems.JqGridColumn;
import com.lomboardrisk.app.ee_new.xsd.jqGrid.cfgItems.JqGridConfiguration;
import com.lomboardrisk.app.ee_new.xsd.schemaSource.AccordionItemType;
import com.lomboardrisk.app.ee_new.xsd.schemaSource.ActionDefinitionType;
import com.lomboardrisk.app.ee_new.xsd.schemaSource.ButtonItemType;
import com.lomboardrisk.app.ee_new.xsd.schemaSource.CategoryType;
import com.lomboardrisk.app.ee_new.xsd.schemaSource.ColumnEditType;
import com.lomboardrisk.app.ee_new.xsd.schemaSource.ColumnSearchType;
import com.lomboardrisk.app.ee_new.xsd.schemaSource.CustomizablePageType;
import com.lomboardrisk.app.ee_new.xsd.schemaSource.DataFieldDisplayType;
import com.lomboardrisk.app.ee_new.xsd.schemaSource.DataFilterType;
import com.lomboardrisk.app.ee_new.xsd.schemaSource.FieldDefinitionType;
import com.lomboardrisk.app.ee_new.xsd.schemaSource.PageDataType;
import com.lomboardrisk.app.ee_new.xsd.template.FlexiblePageFactory;
import com.lomboardrisk.app.ee_new.xsd.util.FlexibleConstants;
import com.lomboardrisk.app.ee_new.xsd.util.FlexiblePageLookupUtils;
import com.lomboardrisk.app.ee_new.xsd.wrapper.EEPageCfgWrapper;
import com.lomboardrisk.app.ee_new.xsd.wrapper.EEPageDataCfgWrapper;

public class FlexiblePageServiceImpl implements FlexiblePageService {

	private static final Logger log = Logger.getLogger(FlexiblePageServiceImpl.class);
	private static Map<Long, EEPageCfgWrapper> customizedEEMap = new HashMap<Long, EEPageCfgWrapper>();
    private static EEPageDataCfgWrapper eeSysCfgWrapper = null;
	
    
	private EEPageCfgWrapper getEECustomizedWrapperInternal(long cfgId, long pageType) throws Exception {
		
		if (customizedEEMap.containsKey(cfgId)) {
			return customizedEEMap.get(cfgId);
		}
		
		// build flexible System configuration
		EEPageDataCfgWrapper dataWrapper = getEEDataCfgWrapperInternal();
		EEPageCfgWrapper cusWrapper = null;
		
		// build flexible System configuration
		JAXBElement<?> tplElement = getJAXBElementByInternal(cfgId,
				pageType, FlexibleConstants.FLEXIBLE_EE_PACKAGE);
		CustomizablePageType pageCfg = (CustomizablePageType) tplElement.getValue();
		
		cusWrapper = new EEPageCfgWrapper(cfgId, pageCfg);
		
		buildDataGridCfg(cusWrapper, dataWrapper);
		buildActionCfg(cusWrapper, dataWrapper);
		
		if (cusWrapper != null) {
			customizedEEMap.put(cfgId, cusWrapper);
		}
			
		return cusWrapper;
	}
	
	private void buildActionCfg(EEPageCfgWrapper cusWrapper,EEPageDataCfgWrapper dataWrapper) {
		Map<String, ActionDefinitionType> sysActions = dataWrapper.getEEActionByPageId(FlexibleConstants.FLEXIBLE_EE_NAME);
		
		List<ButtonItemType> buttonItems = cusWrapper.getButtonItems();

		List<ActionDefinitionType> actionDefs = new ArrayList<ActionDefinitionType>();
		for (Iterator<ButtonItemType> iterator = buttonItems.iterator(); iterator.hasNext();) {
			ButtonItemType buttonItemType = iterator.next();
			
			ActionDefinitionType actionDef = sysActions.get(buttonItemType.getActionRef());
			
			//if the actionRef is not present in Sys Data, return 
			if(actionDef == null) {
				continue ;
			}
			
			//set action properties
			actionDef.setDesc(buttonItemType.getDesc() != null ? buttonItemType.getDesc() : actionDef.getDesc());
			actionDef.setIcon(buttonItemType.getIcon() != null ? buttonItemType.getIcon() : actionDef.getIcon());
			actionDef.setOrder(buttonItemType.getOrder());
			
			actionDefs.add(actionDef);
		}
		
		cusWrapper.setActionBtns(actionDefs);
		
	}

	
	
	private void buildDataGridCfg(EEPageCfgWrapper cusWrapper, EEPageDataCfgWrapper dataWrapper) {
		Map<String, FieldDefinitionType> sysDataFields = dataWrapper.getEEFieldByPageId(FlexibleConstants.FLEXIBLE_EE_NAME);

		List<DataFieldDisplayType> dataFields = cusWrapper.getDataFields();
		
		Map<String, JqGridColumn> colModelMap = new HashMap<String, JqGridColumn>();
		List<JqGridColumn> colModel = new ArrayList<JqGridColumn>();
		String[] colNames = new String[dataFields.size()];
		for (int i=0; i<dataFields.size(); i++) {
			DataFieldDisplayType dataField = dataFields.get(i);
			
			FieldDefinitionType fieldDef = sysDataFields.get(dataField.getFieldNameRef());
			
			JqGridColumn col = new JqGridColumn();
			
			//set sortable column 
			col.setSortable(FlexibleConstants.FLEXIBLE_EE_COL_SORTABLE_DEFAULT);
			if(fieldDef.getSortName() != null) {
				col.setIndex(fieldDef.getSortName());
				col.setSortable(true);
				
				if(dataField.isSortable() != null) {
					col.setSortable(dataField.isSortable());
				}
			}
			
			//set seachable column
			if(fieldDef.isSearchable() != null && fieldDef.isSearchable()) {
				col.setSearch(dataField.isSearchable() == null ? FlexibleConstants.FLEXIBLE_EE_COL_SEARCHABLE_DEFAULT : dataField.isSearchable());
				
				///{value:{0:' ',65:'Pending Review'}}
				ColumnSearchType searchType = fieldDef.getSearchType();
				switch (searchType) {
					case SELECT:
						col.setStype(searchType.value().toLowerCase());
						
						col.setSearchoptions(getSelectSearchOptions(fieldDef.getSearchLookupRef()));
						break;
					case TEXT:
						col.setStype(ColumnSearchType.TEXT.value().toLowerCase());
						
						break;
					case DATE:
						col.setStype(ColumnSearchType.TEXT.value().toLowerCase());
						col.setSearchoptions(getSearchOptions("datePick"));
						break;
					case AJAX:
						col.setStype(ColumnSearchType.TEXT.value().toLowerCase());
						
						col.setSearchoptions(getSearchOptions("autoCompleteRemote"));
						
						break;
					default:
						col.setStype(ColumnSearchType.TEXT.value().toLowerCase());
				}
				
			} else {
				col.setSearch(FlexibleConstants.FLEXIBLE_EE_COL_SEARCHABLE_DEFAULT);
			}
			
			col.setName(fieldDef.getId());
			col.setLabel(fieldDef.getFieldLabel());
			if(fieldDef.getCustomFormatterType() != null) {
				MixBean formatter = new MixBean(fieldDef.getCustomFormatterType(), true);
				col.setFormatter(formatter);
			} else {
				if(fieldDef.getFormatterType() != null) {
					MixBean formatter = new MixBean(fieldDef.getFormatterType().value().toLowerCase(), false);
					col.setFormatter(formatter);
				}
			}
			
			if(fieldDef.isReadOnly()==null || fieldDef.isReadOnly()) {
				col.setEditable(FlexibleConstants.FLEXIBLE_EE_COL_EDITABLE_DEFAULT);
				
			} else {
				boolean hasPrivilege = true;
				String editPrivilege = fieldDef.getEditPrivileges();
				
				if(editPrivilege != null) {
					String privileges[] = editPrivilege.split(",");
					for(int j=0; j<privileges.length; j++) {
						try {
//							hasPrivilege = psr.doIHavePrivilege(privileges[j]);
							if(!hasPrivilege) break;
						} catch (Exception e) {}
					}
				}
				col.setEditable(hasPrivilege);
			}
			
			if(col.isEditable()) {
				if(fieldDef.getEditType() != null) {
					col.setEdittype(fieldDef.getEditType().value().toLowerCase());
					
					Map editoptions = new HashMap();
					
					switch(fieldDef.getEditType()) {
						case CHECK_BOX: 
							editoptions.put("value", "true:false");
							break;
							
						case SELECT: 
							editoptions = getEditOptions(fieldDef.getEditLookupRef());
							break;
						
						case CUSTOM:
							String customFun = fieldDef.getCustomEditFun();
							String customCallBack = fieldDef.getCustomEditCallBack();
							
							if(customFun != null && customFun.trim().length() != 0) {
								editoptions.put(FlexibleConstants.FLEXIBLE_CUSTOM_ELEM, new MixBean(customFun, true));
							}
							
							if(customCallBack != null && customCallBack.trim().length() != 0) {
								editoptions.put(FlexibleConstants.FLEXIBLE_CUSTOM_VALUE, new MixBean(customCallBack, true));
							}
							break;
					}
					if(fieldDef.getFormatterType() != null && fieldDef.getFormatterType().value().equalsIgnoreCase("checkbox")) {
						editoptions.put("value", "true:false");
					}
					
					col.setEditoptions(editoptions);
					
				} else {
					col.setEdittype(ColumnEditType.TEXT.value().toLowerCase());
				}
			}
			
			//client configuration
			colNames[i] = dataField.getDisplayName() == null ? fieldDef.getFieldLabel() : dataField.getDisplayName();
			col.setWidth(dataField.getWidth() == null ? FlexibleConstants.FLEXIBLE_EE_COL_WIDTH_DEFAULT : dataField.getWidth().intValue());
			col.setAlign(dataField.getAlign() == null ? FlexibleConstants.FLEXIBLE_EE_COL_ALIGN_DEFAULT : dataField.getAlign().value());
			col.setResizable(FlexibleConstants.FLEXIBLE_EE_COL_RESIZABLE_DEFAULT);
//			col.setSortable(dataField.isSortable() == null ? FlexibleConstants.FLEXIBLE_EE_COL_SORTABLE_DEFAULT : dataField.isSortable());
			col.setHidden(dataField.isHidden() == null ? FlexibleConstants.FLEXIBLE_EE_COL_HIDDEN_DEFAULT : dataField.isHidden());
			
			colModel.add(col);
			colModelMap.put(col.getName(), col);
		}
		
		JqGridConfiguration jqGridCfg = new JqGridConfiguration();
		
		jqGridCfg.setDatatype(FlexibleConstants.FLEXIBLE_EE_GRID_DATATYPE_DEFAULT);
		jqGridCfg.setUrl(FlexibleConstants.FLEXIBLE_EE_COL_URL_DEFAULT);
		jqGridCfg.setHeadertitles(FlexibleConstants.FLEXIBLE_EE_GRID_SHOW_HEADERS);
		
		JSONManipulateCfg jsonReader = new JSONManipulateCfg();
		jsonReader.setId("workflowId");
		jsonReader.setPage(FlexibleConstants.FLEXIBLE_PAGER_PAGE);
		jsonReader.setTotal(FlexibleConstants.FLEXIBLE_PAGER_TOTAL );
		jsonReader.setRecords(FlexibleConstants.FLEXIBLE_PAGER_RECORDS);
		jsonReader.setRoot(FlexibleConstants.FLEXIBLE_PAGER_ITEMS);
		jsonReader.setRepeatitems(false);

		jqGridCfg.setJsonReader(jsonReader);
		
		jqGridCfg.setAutowidth(true);
		jqGridCfg.setShrinkToFit(false);
		jqGridCfg.setHeight(FlexibleConstants.FLEXIBLE_EE_GRID_HEIGHT);
		
		jqGridCfg.setViewrecords(FlexibleConstants.FLEXIBLE_EE_COL_VIEWRECORD_DEFAULT);
		jqGridCfg.setCellEdit(FlexibleConstants.FLEXIBLE_EE_COL_CELLEDIT_DEFAULT);
		jqGridCfg.setCellsubmit(FlexibleConstants.FLEXIBLE_EE_COL_CELLSUBMIT_DEFAULT);
		jqGridCfg.setMultiselect(FlexibleConstants.FLEXIBLE_EE_COL_MULTIPALSELECT_DEFAULT);
		jqGridCfg.setSortable(FlexibleConstants.FLEXIBLE_EE_COL_SORTABLE_DEFAULT);
		jqGridCfg.setSortname(cusWrapper.getDataGridSortName());
		jqGridCfg.setSortorder(cusWrapper.getDataGridSortOrder());
		
		jqGridCfg.setPager(FlexibleConstants.FLEXIBLE_EE_PAGER_NAME);
		jqGridCfg.setRowNum(20);
		jqGridCfg.setRowList(new int[] {10,20,30});

//		jqGridCfg.setToolbar(new String[]{"true", "top"});
		
		jqGridCfg.setColNames(colNames);
		jqGridCfg.setColModel(colModel);
		
		cusWrapper.setColModelMap(colModelMap);
		cusWrapper.setJqGridCfg(jqGridCfg);
		
	}
	
	private Map getSelectSearchOptions(String methodName) {
		Map searchoptions = new HashMap();
		
		Map value = new LinkedHashMap();
		value.put("0", " ");
		value.putAll(getLookupOptions(methodName));
		
		searchoptions.put("value", value);
		
		return searchoptions;
	}
	
	private Map getSearchOptions(String funName) {
		Map searchoptions = new HashMap();
		
		searchoptions.put("dataInit", new MixBean(funName, true));
		
		return searchoptions;
	}
	private Map getEditOptions(String methodName) {
		
		Map editOptions = new HashMap();
		editOptions.put("value", getLookupOptions(methodName));
		
		return editOptions;
	}
	
	private Map getLookupOptions(String methodName) {
		Map map = null;
		try {
			Method method = FlexiblePageLookupUtils.class.getMethod(methodName, new Class[0]);
			map = (Map)method.invoke(null, new Object[0]);
		} catch (Exception e) {
			log.error("can't find lookup name = " + methodName + " in FlexiblePageLookupUtils class" + e);
		}
		return map == null ? new HashMap() : map; 
	}
	
	private EEPageDataCfgWrapper getEEDataCfgWrapperInternal() throws Exception {
		if(eeSysCfgWrapper != null) {
			return eeSysCfgWrapper;
		}

		JAXBElement<?> tplElement = getJAXBElementByInternal(0,
				FlexibleConstants.PAGE_TYPE_EE_DATA, FlexibleConstants.FLEXIBLE_EE_PACKAGE);
		PageDataType pageDataCfg = (PageDataType) tplElement.getValue();
		eeSysCfgWrapper = new EEPageDataCfgWrapper(pageDataCfg);

		return eeSysCfgWrapper;
		
	}
	
	private JAXBElement<?> getJAXBElementByInternal(long cfgId,
			long pageType, String packageName) throws Exception, JAXBException {
		InputStream tplInputStream;
		if(cfgId == 0) {
			tplInputStream = getSysPageCfgInputStream(pageType);
		} else {
			//byte[] templateContent = pagePM.getTemplateContent(cfgId);
			//tplInputStream = new ByteArrayInputStream(templateContent);
			
			
			tplInputStream = getSysPageCfgInputStream(pageType);
		}
		JAXBContext jc = JAXBContext.newInstance(packageName);
		Unmarshaller u = jc.createUnmarshaller();
		JAXBElement<?> tplElement = (JAXBElement<?>) u.unmarshal(tplInputStream);
		return tplElement;
	}
	
	private InputStream getSysPageCfgInputStream(long pageType) {
		
		InputStream tplInputStream = null;
		if(pageType == FlexibleConstants.PAGE_TYPE_EE_CFG) {
			tplInputStream = FlexiblePageFactory.class.getResourceAsStream(FlexibleConstants.FLEXIBLE_EE_XML_PACKAGE + "flexible-page.xml");
		} else if (pageType == FlexibleConstants.PAGE_TYPE_EE_DATA) {
			tplInputStream = FlexiblePageFactory.class.getResourceAsStream(FlexibleConstants.FLEXIBLE_EE_XML_PACKAGE + "flexible-page-data.xml");
		}
		return tplInputStream;
	}
	
	
	@Override
	public EEPageCfgWrapper getEECustomizedWrapper() {
		long pageType = FlexibleConstants.PAGE_TYPE_EE_CFG;
		long cfgId = 0;
		EEPageCfgWrapper cusWrapper = null;
		try {
			cusWrapper = getEECustomizedWrapperInternal(cfgId, pageType);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return cusWrapper;
	}

	@Override
	public long createEECategory(long cfgId, CategoryType category) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public long modifyEECategory(long cfgId, CategoryType category) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public long removeEECategory(long cfgId, String categoryId) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public long createEECategoryItem(long cfgId, String categoryId,
			AccordionItemType item, DataFilterType dataFilter) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public long modifyEECategoryItem(long cfgId, AccordionItemType item) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public long modifyEECateoryItemPos(long cfgId, String[][] idArrs) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public long removeEECategoryItem(long cfgId, String categoryId,
			String itemId) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public long modifyEEDataFilter(long cfgId, DataFilterType item) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public long modifyEEDataGridPro(long cfgId, String[] hiddenIds,
			Integer[] orders) {
		// TODO Auto-generated method stub
		return 0;
	}

}
